package chd.edu.spzx.cart.service.impl;

import chd.edu.spzx.cart.service.CartService;
import chd.edu.spzx.feign.product.ProductFeignClient;
import chd.edu.spzx.model.entity.h5.CartInfo;
import chd.edu.spzx.model.entity.product.Product;
import chd.edu.spzx.model.entity.product.ProductSku;
import chd.edu.spzx.utils.AuthContextUtil;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Zhang Chaoliang
 * create 2023
 */
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private ProductFeignClient productFeignClient;

    /**
     * 添加到购物车操作
     * @param skuId 商品sku的id值
     * @param skuNum    商品数量
     * @return
     */
    @Override
    public void addToCart(Long skuId, Integer skuNum) {
        //1. 必须是登录状态，获取当前用户id  （作为redis的hash类型的key值）
        // 从ThreadLocal获取用户信息就可以
        Long userId = AuthContextUtil.getUserInfo().getId();
        // 构建hash类型的key名称
        String cartKey = this.getCartKey(userId);

        //2. 购物车放在redis里面
        // 从redis里面获取购物车的数据，根据用户id + skuId获取 （hash类型key + field）
        // hash类型  ： key:userId  field:skuId   value:sku信息CartInfo
        Object cartInfoObj =
                redisTemplate.opsForHash().get(cartKey, String.valueOf(skuId));

        //3. 如果购物车存在添加的商品，把商品数量相加
        CartInfo cartInfo = null;
        if (cartInfoObj != null){ // 添加到购物车的商品之前存在，商品相加
            cartInfo = JSON.parseObject(cartInfoObj.toString(), CartInfo.class);
            //数量相加
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            //设置属性
            cartInfo.setIsChecked(1);  //是否选中
            cartInfo.setUpdateTime(new Date());
        }else {
            //4. 如果购物车没有要添加的商品，直接把商品添加到购物车 （添加到redis里面）
            cartInfo = new CartInfo();

            // 远程调用：通过nacos + openFeign实现 —— 根据skuId获取商品sku信息
            ProductSku productSku = productFeignClient.getBySkuId(skuId);
            //设置相关数据到cartInfo对象中
            cartInfo.setCartPrice(productSku.getSalePrice());
            cartInfo.setSkuNum(skuNum);
            cartInfo.setSkuId(skuId);
            cartInfo.setUserId(userId);
            cartInfo.setImgUrl(productSku.getThumbImg());
            cartInfo.setSkuName(productSku.getSkuName());
            cartInfo.setIsChecked(1);
            cartInfo.setCreateTime(new Date());
            cartInfo.setUpdateTime(new Date());
        }

        // 添加到redis
        redisTemplate.opsForHash().put(cartKey,
                String.valueOf(skuId),
                JSON.toJSONString(cartInfo));
    }
    //工具方法
    private String getCartKey(Long userId) {
        //定义key user:cart:userId
        return "user:cart:" + userId;
    }

    /**
     * 查询购物车
     * @return
     */
    @Override
    public List<CartInfo> getCartList() {
        //1. 构建查询的redis里面的key值，根据当前userId
        Long userId = AuthContextUtil.getUserInfo().getId();
        String cartKey = this.getCartKey(userId);

        //2. 根据key从redis里面hash类型获取所有的value值  cartInfo
        List<Object> valueList = redisTemplate.opsForHash().values(cartKey);

        // 转换类型  List<Object> --- List<CartInfo>
        if (!CollectionUtils.isEmpty(valueList)){
            List<CartInfo> cartInfoList = valueList.stream().map(cartInfoObj ->
                            JSON.parseObject(cartInfoObj.toString(), CartInfo.class))
                    .sorted((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime()))
                    .collect(Collectors.toList());
            return cartInfoList;
        }

        return new ArrayList<>() ;
    }

    /**
     * 删除购物车商品
     * @param skuId
     */
    @Override
    public void deleteCart(Long skuId) {
        // 获取当前登录的用户数据
        Long userId = AuthContextUtil.getUserInfo().getId();
        String cartKey = this.getCartKey(userId);

        //获取缓存对象
        redisTemplate.opsForHash().delete(cartKey,String.valueOf(skuId));
    }

    /**
     * 更新购物车商品选中状态
     * @param skuId
     * @param isChecked
     */
    @Override
    public void checkCart(Long skuId, Integer isChecked) {

        //1. 构建查询的redis里面的key值，根据当前userId
        Long userId = AuthContextUtil.getUserInfo().getId();
        String cartKey = this.getCartKey(userId);

        //2. 判断key是否包含filed
        Boolean hasKey = redisTemplate.opsForHash().hasKey(cartKey, String.valueOf(skuId));

        if (hasKey){
            //3. 根据key + field把value获取出来
            String cartInfoSting =
                    redisTemplate.opsForHash().get(cartKey, String.valueOf(skuId)).toString();

            //4. 更新value里面选中状态
            CartInfo cartInfo = JSON.parseObject(cartInfoSting, CartInfo.class);
            cartInfo.setIsChecked(isChecked);

            //5. 返回到redis的hash类型里面
            redisTemplate.opsForHash().put(cartKey,
                    String.valueOf(skuId),
                    JSON.toJSONString(cartInfo));
        }
    }

    /**
     * 更新购物车商品全部选中状态
     * @param isChecked
     */
    @Override
    public void allCheckCart(Integer isChecked) {
        //1. 构建查询的redis里面的key值，根据当前userId
        Long userId = AuthContextUtil.getUserInfo().getId();
        String cartKey = this.getCartKey(userId);

        //2. 根据key获取购物车所有的value值
        List<Object> objectList = redisTemplate.opsForHash().values(cartKey);

        //类型转换 List<Object> --- List<CartInfo>
        if (!CollectionUtils.isEmpty(objectList)){
            List<CartInfo> cartInfoList =
                    objectList.stream().map(object ->
                            JSON.parseObject(object.toString(), CartInfo.class))
                            .collect(Collectors.toList());

            //3. 把每一个商品的isChecked进行更新
            cartInfoList.forEach(cartInfo -> {
                cartInfo.setIsChecked(isChecked);
                redisTemplate.opsForHash().put(cartKey,
                        String.valueOf(cartInfo.getSkuId()),
                        JSON.toJSONString(cartInfo));
            });
        }
    }

    /**
     * 清空购物车
     */
    @Override
    public void clearCart() {
        //1. 构建查询的redis里面的key值，根据当前userId
        Long userId = AuthContextUtil.getUserInfo().getId();
        String cartKey = this.getCartKey(userId);

        //2. 根据key删除redis里面数据
        redisTemplate.delete(cartKey);
    }

    /**
     * 远程调用： 订单结算使用，获取购物车选中的商品列表
     * @return
     */
    @Override
    public List<CartInfo> getAllCkecked() {
        //1. 获取userId,构建key
        Long userId = AuthContextUtil.getUserInfo().getId();
        String cartKey = this.getCartKey(userId);

        //2. 根据key获取购物车所有商品
        List<Object> objectList = redisTemplate.opsForHash().values(cartKey);
        if (!CollectionUtils.isEmpty(objectList)){
            List<CartInfo> cartInfoList = objectList.stream().map(object ->
                            JSON.parseObject(object.toString(), CartInfo.class))
                    .filter(cartInfo -> cartInfo.getIsChecked() == 1) //选中
                    .collect(Collectors.toList());
            return cartInfoList;
        }
        return new ArrayList<>() ;
    }

    /**
     * 远程调用 —— 删除生成订单的购物车商品
     * @return
     */
    @Override
    public void deleteChecked() {
        //1. 获取userId,构建key
        Long userId = AuthContextUtil.getUserInfo().getId();
        String cartKey = this.getCartKey(userId);

        //根据key获取redis所有value值
        List<Object> objectList = redisTemplate.opsForHash().values(cartKey);

        //删除选中商品
        if(!CollectionUtils.isEmpty(objectList)){
            objectList.stream().map(object ->
                            JSON.parseObject(object.toString(),CartInfo.class))
                    .filter(cartInfo -> cartInfo.getIsChecked() == 1)
                    .forEach(cartInfo ->
                            redisTemplate.opsForHash()
                                    .delete(cartKey,String.valueOf(cartInfo.getSkuId())));
        }

    }


}
